1 00:00:01,130 --> 00:00:01,790 Hey there! 2 00:00:01,790 --> 00:00:06,980 Since the story section of our game is going to be entirely first person based, I want to add the ability 3 00:00:06,980 --> 00:00:11,750 for the player's torso to tilt towards the direction of their camera, whether they are facing up or 4 00:00:11,750 --> 00:00:12,170 down. 5 00:00:12,200 --> 00:00:16,640 This will allow us to easily move any tools that the players are holding in the direction of their camera's 6 00:00:16,640 --> 00:00:17,270 tilt. 7 00:00:17,270 --> 00:00:22,100 So inside of the spawn, I've added this part here in the workspace with a light inside of it, so we 8 00:00:22,100 --> 00:00:24,020 can easily see the player's character. 9 00:00:24,020 --> 00:00:25,670 And if we go and play test. 10 00:00:26,720 --> 00:00:28,460 And we go to our character here. 11 00:00:28,460 --> 00:00:32,330 There are these different constraints that connect the different body parts to each other. 12 00:00:32,330 --> 00:00:37,550 So for example, there's a motor six d constraint that connects our arms to the torso, a constraint 13 00:00:37,550 --> 00:00:42,110 that connects the upper torso to the lower torso, the legs to the lower torso, and things like that. 14 00:00:42,110 --> 00:00:47,570 So if we go into our character and we go to something like our upper torso, there is a motor six d 15 00:00:47,570 --> 00:00:48,590 constraint in here. 16 00:00:48,590 --> 00:00:52,760 And it contains two properties, one keyframe here and one keyframe here. 17 00:00:52,760 --> 00:00:58,100 Now these two keyframes represent the different offsets for part zero and part one. 18 00:00:58,100 --> 00:01:04,370 So C zero is the offset keyframe for part zero, and C one is the offset for part one. 19 00:01:04,370 --> 00:01:06,950 So these two different parts have their own keyframe. 20 00:01:06,950 --> 00:01:12,380 And these keyframes get added on to those keyframes to, you know, create an offset. 21 00:01:12,380 --> 00:01:18,170 So if I were to reset this to be something like a zero, as you can see, my torso moves down. 22 00:01:19,730 --> 00:01:25,610 But if I apply that -0.8 offset again, my torso returns back to its original position. 23 00:01:25,640 --> 00:01:31,730 Now, using these different offsets, we can actually rotate our player's torso in the direction of 24 00:01:31,730 --> 00:01:32,720 our player's camera. 25 00:01:32,720 --> 00:01:36,110 So what we could do is we could get the direction of where our camera is facing. 26 00:01:36,110 --> 00:01:41,060 So for example, if our camera is facing downwards, then we can have our torso rotate in the direction 27 00:01:41,060 --> 00:01:45,650 where our camera is facing downwards and rotate it upwards when our camera is facing upwards. 28 00:01:45,650 --> 00:01:50,450 So in order to do this, we have a script inside of starter character scripts, which is called Torso 29 00:01:50,480 --> 00:01:51,020 Tilt. 30 00:01:51,320 --> 00:01:54,140 And inside of here we're going to need a few variables. 31 00:01:54,140 --> 00:01:56,690 One is going to be the camera of our player. 32 00:01:58,200 --> 00:02:05,130 We're going to need the character, which you can do by either using the player service to get the local 33 00:02:05,130 --> 00:02:10,230 character, or another way you could do it, because in the previous scripts we showed it by doing, 34 00:02:10,230 --> 00:02:12,030 uh, player dot character. 35 00:02:12,030 --> 00:02:17,970 But since this script is going to end up inside of our character, you could also do script dot parent 36 00:02:17,970 --> 00:02:20,130 and this will give us the character as well. 37 00:02:20,370 --> 00:02:23,310 And then from this point we can get the root part of our character as well. 38 00:02:23,310 --> 00:02:27,990 So we do character and we'll wait for the child humanoid root part. 39 00:02:28,470 --> 00:02:33,510 And then we're also going to get the upper torso of our character as well, which is character. 40 00:02:33,510 --> 00:02:36,660 Wait for child upper torso. 41 00:02:37,900 --> 00:02:42,430 Now, another thing we want to get is that motor 60 constraint called waste. 42 00:02:42,430 --> 00:02:44,470 So this variable will be called waste. 43 00:02:44,470 --> 00:02:48,130 And inside of our upper torso we're going to wait for this waste constraint. 44 00:02:48,990 --> 00:02:54,000 And something that's very important is that we need to store the Y offset of the first C frame that 45 00:02:54,000 --> 00:02:55,650 is stored inside of that constraint. 46 00:02:55,650 --> 00:02:57,390 We need to keep that Y offset. 47 00:02:57,390 --> 00:03:01,680 So that way our torso doesn't move downwards to a different position. 48 00:03:01,680 --> 00:03:04,020 So we'll create a variable called y offset. 49 00:03:04,020 --> 00:03:09,180 And that will be equal to the waist dot c zero dot y. 50 00:03:09,180 --> 00:03:12,180 And we can also denote this as a motor six d. 51 00:03:12,970 --> 00:03:18,100 And we need to make sure we store that y offset that is applied on this constraint here. 52 00:03:18,100 --> 00:03:21,190 Now we're actually going to also need to grab a service. 53 00:03:21,190 --> 00:03:22,450 So I'm going to copy this. 54 00:03:22,450 --> 00:03:25,330 And I'll make a section up here for services. 55 00:03:25,330 --> 00:03:29,140 And the only service that we're going to need is the run service. 56 00:03:29,140 --> 00:03:32,890 So run service is equal to game get service run service. 57 00:03:32,890 --> 00:03:37,690 And this is because we're going to be updating the rotation of our player every single frame. 58 00:03:38,080 --> 00:03:42,430 So in the run service we're going to connect to the render step event. 59 00:03:44,410 --> 00:03:52,420 And what this is going to do is, is it going to calculate the rotation of our camera relative to our 60 00:03:52,420 --> 00:03:53,200 root part. 61 00:03:53,200 --> 00:04:00,070 And then based on that, it's going to rotate the waist constraint that we have inside of our upper 62 00:04:00,070 --> 00:04:00,940 torso. 63 00:04:01,430 --> 00:04:06,860 Now, since this was going to be firing every single frame and there are several global functions we're 64 00:04:06,860 --> 00:04:11,870 going to be using in here, it's better for us to store these global functions in local memory. 65 00:04:11,870 --> 00:04:16,160 That way it's more performant when we're executing this function in render step. 66 00:04:16,160 --> 00:04:20,720 So the global functions we're going to need is for creating a new key frame. 67 00:04:20,720 --> 00:04:22,640 So we'll call it CF new. 68 00:04:22,640 --> 00:04:26,960 Another one is for creating a new key frame with some angles. 69 00:04:26,960 --> 00:04:28,760 So that's CF angles. 70 00:04:28,760 --> 00:04:35,960 And then we'll need a reference to a function in the math library called a sine which stands for arc 71 00:04:35,960 --> 00:04:36,590 sine. 72 00:04:36,770 --> 00:04:38,960 So we'll make those references. 73 00:04:38,960 --> 00:04:42,110 So C frame dot new C frame dot angles. 74 00:04:42,110 --> 00:04:45,710 And then math dot a sine. 75 00:04:45,830 --> 00:04:49,910 Now what we're going to do inside of this handler is first make sure that waste actually exists. 76 00:04:49,910 --> 00:04:56,090 Because if our character dies and this um, constraint here gets destroyed, we're going to end up with 77 00:04:56,090 --> 00:04:56,600 errors. 78 00:04:56,600 --> 00:05:01,880 So if waste does not exist, then we're just going to return. 79 00:05:02,240 --> 00:05:06,470 Otherwise what we're going to do is we're going to get the direction that our camera is facing. 80 00:05:06,470 --> 00:05:09,830 So we're going to make a variable called cam direction. 81 00:05:09,920 --> 00:05:13,910 And what we could do is we can get the camera dot c frame. 82 00:05:13,910 --> 00:05:16,970 And we want to make this camera C frame. 83 00:05:17,180 --> 00:05:21,800 Uh, we want to calculate the C frame relative to the C frame of our root part. 84 00:05:21,800 --> 00:05:28,550 So basically we want the c frame of our root part to act as the origin when we calculate the camera 85 00:05:28,550 --> 00:05:29,180 C frame. 86 00:05:29,180 --> 00:05:36,290 Because this C frame is going to give us a bunch of numbers based on the game's global, um, origin, 87 00:05:36,290 --> 00:05:37,640 which is 000. 88 00:05:37,640 --> 00:05:41,780 But we want to use the root part of our character as the origin for the C frame. 89 00:05:41,780 --> 00:05:42,890 How can we do that? 90 00:05:42,890 --> 00:05:48,380 Well, what we could do is we could reference our root part, and then we can get the c frame of our 91 00:05:48,380 --> 00:05:49,160 root part. 92 00:05:49,160 --> 00:05:57,410 And the C frame has a function called two object space, which allows us to calculate a c frame using 93 00:05:57,410 --> 00:05:59,870 this c frame as the origin point. 94 00:05:59,870 --> 00:06:05,510 And that means we can pass our, um, camera C frame in here. 95 00:06:05,510 --> 00:06:11,000 And then to get the direction that this camera is facing based on the root part as the origin of the 96 00:06:11,030 --> 00:06:13,010 C frame, we can get the look vector. 97 00:06:13,850 --> 00:06:17,840 Now using this look vector, we can easily just grab the y component of it. 98 00:06:17,840 --> 00:06:24,080 And for example, if the y component of our look vector is one, that means our player is looking directly 99 00:06:24,080 --> 00:06:24,770 upwards. 100 00:06:24,770 --> 00:06:29,540 If the y component is negative one, that means our player is looking directly downwards. 101 00:06:29,570 --> 00:06:35,420 Now, I don't want my player's torso to be able to look directly upwards and directly downwards, because 102 00:06:35,420 --> 00:06:40,790 that means our torso will be completely parallel with the floor and that will look very weird. 103 00:06:40,820 --> 00:06:47,990 So what I'm going to do is I'm going to restrict the ability for the player's, uh, torso rotation 104 00:06:47,990 --> 00:06:50,150 to extend past a certain point. 105 00:06:50,180 --> 00:06:57,560 So, for example, if the camera direction dot y, if this becomes greater than a value like 0.4, then 106 00:06:57,560 --> 00:07:00,740 we do not want to rotate our torso any further. 107 00:07:02,010 --> 00:07:04,680 Same thing goes for if we want to look down too far. 108 00:07:04,680 --> 00:07:12,870 So if the cam direction dot y becomes less than or equal to -0.7, then we want to stop it there as 109 00:07:12,870 --> 00:07:13,050 well. 110 00:07:13,050 --> 00:07:17,790 We don't want to rotate further than where our camera is looking down. 111 00:07:19,250 --> 00:07:23,720 Otherwise we'll apply the rotation to our waist constraint. 112 00:07:24,170 --> 00:07:30,200 So what we're going to do for example in this section is we're going to get our waist motor 60 constraint. 113 00:07:30,200 --> 00:07:35,090 And we're going to get the key frame offset for the first part. 114 00:07:35,090 --> 00:07:38,660 And what we're going to do is we're going to set it equal to itself. 115 00:07:38,780 --> 00:07:44,990 But then we're going to use the lerp function or the linear interpolation function on the key frame. 116 00:07:45,260 --> 00:07:48,380 So we're going to create a new key frame here. 117 00:07:48,380 --> 00:07:51,500 And this key frame is going to be zero. 118 00:07:51,500 --> 00:07:57,110 But it's going to keep our y offset and then zero for the other position. 119 00:07:57,110 --> 00:08:03,020 So the key frame here is the exact same as the key frame that is stored in C zero. 120 00:08:03,020 --> 00:08:06,110 Except we're going to create a different rotation for it. 121 00:08:06,110 --> 00:08:11,510 So instead of having a rotation of zero zero what we're going to do is we're going to create a new key 122 00:08:11,510 --> 00:08:13,460 frame with a different rotation. 123 00:08:14,320 --> 00:08:20,470 And what we have to do here is we're going to have to use our a sine function. 124 00:08:21,040 --> 00:08:22,690 Now what is a sign? 125 00:08:22,690 --> 00:08:25,240 Well, again, a sign stands for arc sign. 126 00:08:25,240 --> 00:08:29,860 And this is the inverse function to the regular sign function in trigonometry. 127 00:08:29,860 --> 00:08:33,940 Now I'm not going to be explaining trigonometry in this lecture because that would probably be longer 128 00:08:33,940 --> 00:08:35,200 than this entire course. 129 00:08:35,200 --> 00:08:41,140 But basically in algebra when you have a function like y is equal to x, blah, blah, blah, if you 130 00:08:41,140 --> 00:08:45,820 wanted to try to find the inverse of that function, you would have to swap the positions of x and y 131 00:08:45,820 --> 00:08:47,260 and then solve for y. 132 00:08:47,260 --> 00:08:51,550 Unfortunately, that becomes a little bit more complicated with the sine function, which is why the 133 00:08:51,550 --> 00:08:54,220 inverse or arc sine function exists. 134 00:08:54,220 --> 00:08:59,170 Now, most people have probably heard of the sine function because it generates the popular sine wave 135 00:08:59,170 --> 00:09:04,720 pattern, where you have a wave going up and down, repeating itself over and over for infinity, stretching 136 00:09:04,720 --> 00:09:06,490 across the x axis. 137 00:09:06,490 --> 00:09:09,760 Now the inverse sine function does the exact same thing. 138 00:09:09,760 --> 00:09:16,360 However, instead of the sine wave going along the x axis, the sine wave goes along the y axis. 139 00:09:16,600 --> 00:09:22,900 Now we need to use this arc sine function in order to get the rotation in radians that we need to apply 140 00:09:22,900 --> 00:09:27,910 on the x axis for our waste constraint here. 141 00:09:28,240 --> 00:09:34,690 So what we need to do is we need to pass our cam direction dot y value. 142 00:09:34,720 --> 00:09:39,910 Now because in this if statement section we want to limit this from going beyond 0.4. 143 00:09:39,940 --> 00:09:42,880 Then instead we can replace this value here with 0.4. 144 00:09:42,880 --> 00:09:48,220 And again this is representing our look vector value for the y direction. 145 00:09:48,220 --> 00:09:54,970 And passing this number to the a sine function is going to return back to us a number that represents 146 00:09:54,970 --> 00:09:59,440 the rotation on the x axis in radians. 147 00:09:59,440 --> 00:10:04,240 And that means we don't have to rotate this on the y axis, and we don't have to rotate this on the 148 00:10:04,240 --> 00:10:05,200 z axis. 149 00:10:05,590 --> 00:10:09,520 And then we want to do basically the exact same thing here as well. 150 00:10:09,730 --> 00:10:12,640 But instead we want to limit the number here. 151 00:10:13,220 --> 00:10:15,470 To -0.7. 152 00:10:15,470 --> 00:10:20,540 And then for this last section, if our camera direction is between these two values, then we can do 153 00:10:20,540 --> 00:10:26,510 basically the exact same thing, but instead just pass the cam direction dot y component. 154 00:10:26,900 --> 00:10:33,500 So what this is doing right here is that it's creating a new C frame that has the exact same position 155 00:10:33,500 --> 00:10:41,510 as our C0C frame, but it is creating a rotation on that C frame based on the camera's direction or 156 00:10:41,510 --> 00:10:45,200 aka which direction in the y axis is our camera facing. 157 00:10:45,200 --> 00:10:51,230 So if our camera is facing downwards, then this function is going to give us a value that represents 158 00:10:51,230 --> 00:10:57,470 the rotation on the x axis to rotate our waist to face downwards. 159 00:10:57,800 --> 00:11:01,880 Otherwise, if our camera is facing upwards, then it's going to give us a value that represents the 160 00:11:01,880 --> 00:11:05,600 rotation on the x axis to make the torso look upwards. 161 00:11:05,630 --> 00:11:12,020 Now, one more value that we have to pass to the lerp function is an alpha number, and this alpha number 162 00:11:12,020 --> 00:11:19,460 represents um basically the percentage between the two different C frames. 163 00:11:19,460 --> 00:11:23,000 So we have our regular way C frame with no rotation. 164 00:11:23,000 --> 00:11:28,070 And we have this new C frame with this new rotation that we've applied on the x axis. 165 00:11:28,070 --> 00:11:33,320 And the alpha represents what percentage of the way we want to make it to this new rotation. 166 00:11:33,320 --> 00:11:38,930 So if I pass the number like 0.5 then it would go halfway to this rotation. 167 00:11:38,930 --> 00:11:43,370 So basically the value that gets returned from this assign function will be cut in half. 168 00:11:43,370 --> 00:11:51,260 Now, since this function is going to be executing every single frame, that means our way C frame is 169 00:11:51,260 --> 00:11:56,210 slowly going to move to this new position halfway each time this gets executed. 170 00:11:56,210 --> 00:11:57,590 And I'll show you what I mean. 171 00:11:57,590 --> 00:12:03,920 So if I set this number to something very low, like 0.01, and I copy this and do it for the same thing 172 00:12:03,920 --> 00:12:06,890 on each of these lerp functions. 173 00:12:07,710 --> 00:12:11,580 And I go back to test our game here. 174 00:12:13,400 --> 00:12:18,380 What I'm going to do is I'm going to go to my player's character, and I'm going to go down to my upper 175 00:12:18,380 --> 00:12:20,930 torso and we're going to look at our waist motor. 176 00:12:20,930 --> 00:12:22,010 Six d constraint. 177 00:12:22,620 --> 00:12:28,140 Now, as you can already see, our orientation is changing here to match where our camera is facing. 178 00:12:28,290 --> 00:12:35,820 So if I were to make my camera look upwards, as you can see, my character is moving very slowly upwards. 179 00:12:35,880 --> 00:12:41,520 And as you can see, this orientation value is continuing to increase and it keeps getting slower and 180 00:12:41,520 --> 00:12:43,440 slower as each second goes by. 181 00:12:43,470 --> 00:12:51,600 Now the reason for this is because we are linearly interpolating the key frame to this new rotation. 182 00:12:51,600 --> 00:12:54,360 But we're only moving 1% each time. 183 00:12:54,750 --> 00:13:01,680 And as we keep updating this C0, um, when this function gets called again, it'll get that new rotation 184 00:13:01,680 --> 00:13:06,540 value and again try to move it 1% of the way to this new value. 185 00:13:06,540 --> 00:13:08,430 So it's going to keep moving. 186 00:13:09,210 --> 00:13:15,390 As you can see, it's still slowly going up until eventually it reaches the new value and now it stops. 187 00:13:15,660 --> 00:13:20,550 But basically it makes our rotation of the torso very slow. 188 00:13:21,800 --> 00:13:27,350 Now, if you wanted to remove this kind of animation style effect at all, then you would just replace 189 00:13:27,350 --> 00:13:35,570 this number with one, which means you are setting the C frame and the C zero property to a new C frame, 190 00:13:35,570 --> 00:13:42,140 which is basically the C frame that we passed here because it stands for 100%, or you're moving 100% 191 00:13:42,140 --> 00:13:42,770 of the way there. 192 00:13:42,770 --> 00:13:44,180 So if we test this again. 193 00:13:45,710 --> 00:13:48,440 And if we rotate the player downwards. 194 00:13:48,620 --> 00:13:49,040 See? 195 00:13:49,040 --> 00:13:50,960 It instantly moves to the new position, right? 196 00:13:50,960 --> 00:13:56,090 There's no there's no delay at all for moving to the new position, because we are interpolating the 197 00:13:56,090 --> 00:13:58,400 key frame instantly to the new position. 198 00:13:58,400 --> 00:14:03,590 Now, if you wanted to make this look more animated, we could of course reduce this number. 199 00:14:03,590 --> 00:14:09,020 So I found a number of like 0.25 to actually look quite nice. 200 00:14:09,020 --> 00:14:16,850 So that means every single time this function gets executed, uh, our rotation is being applied one 201 00:14:16,850 --> 00:14:20,660 fourth of the way, or 25% of the way each time this gets executed. 202 00:14:20,810 --> 00:14:26,120 So basically, what I want you to imagine is, let's say we have a rotation of zero, zero and zero, 203 00:14:26,120 --> 00:14:31,580 and we want to make a rotation of like let's say 800. 204 00:14:31,580 --> 00:14:32,300 Right. 205 00:14:32,300 --> 00:14:38,300 Well, through the first iteration or when this function first gets executed, it's going to look at 206 00:14:38,300 --> 00:14:42,170 the difference between the key frame and this key frame which is eight. 207 00:14:42,170 --> 00:14:42,920 Right. 208 00:14:42,920 --> 00:14:51,590 And it's going to make the key frame be 0.25% of the way to eight, which means we would have a new 209 00:14:51,590 --> 00:14:55,340 value of 200. 210 00:14:56,240 --> 00:14:59,930 So now our C zero is updated to 200. 211 00:14:59,930 --> 00:15:02,390 And then this function is going to get executed again. 212 00:15:02,390 --> 00:15:04,250 And now it's going to look. 213 00:15:05,120 --> 00:15:08,690 At our value of two zero 0 to 8 zero zero. 214 00:15:08,690 --> 00:15:16,610 And it's going to be like, okay, what is 25% of the way to 800 when our starting value is two? 215 00:15:16,910 --> 00:15:20,810 So this is not applying the rotation in a linear fashion. 216 00:15:20,810 --> 00:15:26,690 Instead, it's kind of applying the rotation in a curve fashion where it starts fast at the beginning, 217 00:15:26,690 --> 00:15:33,710 but then it begins to slow down, which gives us a nice kind of animated effect when we are applying 218 00:15:33,710 --> 00:15:35,960 the rotation on our waist constraint. 219 00:15:37,100 --> 00:15:43,640 So when we test this out here, when we rotate upwards, we can see there is a very slight delay and 220 00:15:43,640 --> 00:15:45,230 it looks nice and animated. 221 00:15:45,230 --> 00:15:49,850 So when I look all the way down, as you can see, we reach that barrier where we can have the character 222 00:15:49,850 --> 00:15:53,870 no longer look down any further because of that constraint we added. 223 00:15:53,870 --> 00:15:58,370 And then when I look upwards, as you can see, our character stops and no longer moves upwards anymore, 224 00:15:58,370 --> 00:15:58,850 right? 225 00:15:59,470 --> 00:16:07,870 Now, let's say I decided to get rid of these conditions and apply no constraint at all to our waist 226 00:16:07,870 --> 00:16:08,380 keyframe. 227 00:16:08,380 --> 00:16:10,990 So let's say I were to comment this out. 228 00:16:11,540 --> 00:16:13,100 And instead. 229 00:16:13,740 --> 00:16:19,080 I were to just apply, you know, this new rotation to the C frame, then there's going to be no limit 230 00:16:19,080 --> 00:16:22,530 on how far we can look down and how far we can look up. 231 00:16:22,620 --> 00:16:27,480 So that means because I got rid of those limits, now I can look all the way up. 232 00:16:27,480 --> 00:16:30,930 And as you can see, my torso is completely rotated incorrectly. 233 00:16:30,930 --> 00:16:35,880 And that means I can also look all the way down in my torso is rotated all the way down. 234 00:16:36,390 --> 00:16:42,240 Now, we don't want our torso to rotate this much, which is why we've added these limits here onto 235 00:16:42,240 --> 00:16:44,970 how far the torso can actually rotate. 236 00:16:45,540 --> 00:16:50,520 And of course, you can adjust these values to your liking if you want the torso to be able to rotate 237 00:16:50,520 --> 00:16:55,530 a little bit more upwards, then you can increase this value to something like maybe 0.5 or 0.6. 238 00:16:55,530 --> 00:17:00,720 And if you want the torso to be able to rotate more downwards, then of course you can increase this 239 00:17:00,720 --> 00:17:05,220 number as well to like -0.8 or -0.9, something like that. 240 00:17:05,760 --> 00:17:11,880 But I found the values of 0.4 and -0.7 respectively, to be pretty good for what we're doing in our 241 00:17:11,880 --> 00:17:12,390 game. 242 00:17:12,930 --> 00:17:17,940 Otherwise, that's how we can use trigonometry to apply rotation on our player's torso. 243 00:17:17,970 --> 00:17:22,920 Now, I don't really expect you to understand trigonometry unless you've already known trigonometry 244 00:17:22,920 --> 00:17:25,440 or you've taken a math class on trigonometry. 245 00:17:25,440 --> 00:17:30,840 But otherwise, all you need to know is that this is just some simple math that we're calculating to 246 00:17:30,870 --> 00:17:38,490 linearly interpolate our C frame to a new rotation based on the look vector of our camera. 247 00:17:38,790 --> 00:17:40,530 So I'll see you in the next lecture.